package van.planifolia.worktest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Intellij IDEA<br>
 *
 * @author Planifolia.Van
 * @version 1.0
 * @date 2022/11/1 17:15
 */
public class SafeArrayAddSource {
    static String[] stringSp = new String[2];
    static int index = 0;

    public static void main(String[] args) throws InterruptedException {
        SafeArrayAddSource.lockTest();
    }
    public static void synTest() throws InterruptedException {
        // 创建一个String数组来作为存放数据的容器
        //然后创建两个线程让这两个线程分别给这个数组添加数据
        Thread t2 = new Thread(() -> {
            // 想要解决线程不安全的问题我们要在这使用synchronized
            // 锁来保证当前修改的对象只能被一个线程修改，其他人想进入得排队
            synchronized (stringSp) {
                if (stringSp[index] == null) {
                    stringSp[index] = "hello";
                    index++;
                }
            }
        }, "线程A");
        Thread t1 = new Thread(() -> {
            synchronized (stringSp) {
                if (stringSp[index] == null) {
                    stringSp[index] = "word";
                    index++;
                }
            }
        }, "线程B");
        t2.start(); t1.start(); t2.join(); t1.join();
        // 首先我们要保证这条打印语句要在上面两个赋值操作执行完毕之后在执行，所以我们要让t1，t2线程插队到Main线程的前面
        // 然后我们执行代码会发现 当我们打印的时候小概率的情况下会发现某一个变量可能会是null，这种就是出现了线程不安全的问题
        // 两个线程本应该分别修改两个数组位置的
        // 但是他们因为线程切换的问题操作了同一个字符串，所以我们需要使用锁来解决这种线程不安全的问题
        System.out.println(Arrays.toString(stringSp));
    }
    public static void lockTest() throws InterruptedException {
        // 同样也是创建一个数组来作为存放的容器
        String[] strings = new String[2];
        // 不过我们要在这创建一个Lock锁的实现类
        Lock lock = new ReentrantLock();
        //启动俩线程来分别插入
        Thread t1 = new Thread( ()->{
            //进入判断钱上锁
            lock.lock();
            try {
                if (strings[index] == null) {
                    strings[index] = "hello";
                    index++;
                }
            }finally {
                //解锁一定要放在finally中
                lock.unlock();
            }
        } ,"线程A");
        Thread t2 = new Thread( ()->{
            //进入判断钱上锁
            lock.lock();
            try {
                if (strings[index] == null) {
                    strings[index] = "word";
                    index++;
                }
            }finally {
                //解锁一定要放在finally中
                lock.unlock();
            }

        } ,"线程B");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(Arrays.toString(strings));
    }

}
